package cc.rengu.redp.bizimpl.upmp.service.impl;

import cc.rengu.redp.bizimpl.bean.Tree;
import cc.rengu.redp.bizimpl.constant.UpmpConstant;
import cc.rengu.redp.bizimpl.enums.ChannelTypeEnum;
import cc.rengu.redp.bizimpl.enums.MenuTypeEnum;
import cc.rengu.redp.bizimpl.enums.UserTypeEnum;
import cc.rengu.redp.bizimpl.manager.UpmpUserManager;
import cc.rengu.redp.bizimpl.upmp.dao.UpmpMenuMapper;
import cc.rengu.redp.bizimpl.upmp.domain.UpmpMenu;
import cc.rengu.redp.bizimpl.upmp.domain.UpmpSysParam;
import cc.rengu.redp.bizimpl.upmp.service.IUpmpMenuService;
import cc.rengu.redp.bizimpl.upmp.service.IUpmpSysParamService;
import cc.rengu.redp.bizimpl.upmp.service.IUserCommonFunService;
import cc.rengu.redp.bizimpl.upmp.vo.UpmpMenuVO;
import cc.rengu.redp.bizimpl.upmp.vo.UpmpUserInfoVO;
import cc.rengu.redp.bizimpl.upmp.vo.UserCommonFunVO;
import cc.rengu.redp.bizimpl.utils.CommonUtils;
import cc.rengu.redp.bizimpl.utils.RedpUpmpUtil;
import cc.rengu.redp.bizimpl.utils.TreeUtil;
import cc.rengu.redp.common.domain.QueryRequest;
import cc.rengu.redp.common.exception.RedpException;
import cc.rengu.redp.common.utils.DateUtil;
import cc.rengu.redp.common.utils.SortUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author System
 */
@Service("upmpMenuService")
@DS("upmp")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)@Slf4j
public class UpmpMenuServiceImpl extends ServiceImpl<UpmpMenuMapper, UpmpMenu> implements IUpmpMenuService {
    @Autowired
    private IUpmpSysParamService upmpSysParamService;
    @Autowired
    private UpmpUserManager upmpUserManager;
    @Autowired
    private IUserCommonFunService userCommonFunService;

    @Override
    public List<UpmpMenu> findUserPermissions(String userId) {
        return this.baseMapper.findUserPermissions(userId);
    }

    @Override
    public List<UpmpMenu> findUserMenus(String userId) {
        return this.baseMapper.findUserMenus(userId);
    }

    @Override
    public IPage<UpmpMenuVO> findPermsPageList(UpmpMenuVO menuVO, QueryRequest request) throws RedpException {

        Page<UpmpMenu> page = new Page<>();
        SortUtil.handlePageSort(request, page, "id", UpmpConstant.ORDER_ASC, true);
        try {
            //防止点击重置按钮后不传法人行查询
            IPage<UpmpMenu> userIPage =  this.baseMapper.findPermsPageList(page,menuVO);
            List<UpmpMenu> userList = userIPage.getRecords();
            List<UpmpMenuVO> uservoList = Lists.newArrayList();
            /*userList.forEach(userItem -> {
                UpmpMenuVO vo = new UpmpMenuVO();
                BeanUtils.copyProperties(userItem,vo);
                uservoList.add(vo);
            });*/
            for(int i=0;i<userList.size();i++){
                UpmpMenu userItem = userList.get(i);
                UpmpMenuVO vo = new UpmpMenuVO();
                BeanUtils.copyProperties(userItem,vo);
//                vo.setId(String.valueOf((userIPage.getCurrent()-1)*userIPage.getSize()+i));
                uservoList.add(vo);
            }

            IPage<UpmpMenuVO> userVOIPage = new Page<UpmpMenuVO>();
            BeanUtils.copyProperties(userIPage,userVOIPage);
            userVOIPage.setRecords(uservoList);
            return userVOIPage;
        } catch (Exception e) {
            log.error("查询菜单权限数据异常", e);
            return null;
        }
    }

    @Override
    public IPage<UpmpMenuVO> permsPrivilegePageList(UpmpMenuVO menuVO, QueryRequest request) throws RedpException {

        UpmpSysParam defaultInst = upmpSysParamService.getById(UpmpConstant.DEAFULT_INST_PARAM_ID);
        //当前用户ID
        UpmpUserInfoVO currentUser = RedpUpmpUtil.getCurrentUser(defaultInst.getPrimaryValue());
        log.info("currentUser:{}",currentUser);
        if(currentUser.isAdmin()){
            log.info("user {} is admin",currentUser.getLoginId());
            if(StringUtils.isEmpty(menuVO.getInstId())){
                log.warn("获取可配置是否需要审核的权限时未传入instId,使用当前用户所属instId");
                menuVO.setInstId(currentUser.getInstId());
            }
        }else{
            log.warn("非管理员角色获取可配置是否需要审核的权限时使用当前用户所属instId");
            menuVO.setInstId(currentUser.getInstId());
        }
        if(StringUtils.isEmpty(menuVO.getInstId())){
            log.error("参数[法人行]为空");
            IPage<UpmpMenuVO> userVOIPage = new Page<UpmpMenuVO>();
            userVOIPage.setRecords(null);
            return userVOIPage;
        }
        Page<UpmpMenu> page = new Page<>();
        SortUtil.handlePageSort(request, page, "id", UpmpConstant.ORDER_ASC, true);
        try {
            IPage<UpmpMenu> userIPage =  this.baseMapper.permsPrivilegePageList(page,menuVO);
            List<UpmpMenu> userList = userIPage.getRecords();
            List<UpmpMenuVO> uservoList = Lists.newArrayList();
            /*userList.forEach(userItem -> {
                UpmpMenuVO vo = new UpmpMenuVO();
                BeanUtils.copyProperties(userItem,vo);
                uservoList.add(vo);
            });*/
            for(int i=0;i<userList.size();i++){
                UpmpMenu userItem = userList.get(i);
                UpmpMenuVO vo = new UpmpMenuVO();
                BeanUtils.copyProperties(userItem,vo);
//                vo.setId(String.valueOf((userIPage.getCurrent()-1)*userIPage.getSize()+i));
                uservoList.add(vo);
            }

            IPage<UpmpMenuVO> userVOIPage = new Page<UpmpMenuVO>();
            BeanUtils.copyProperties(userIPage,userVOIPage);
            userVOIPage.setRecords(uservoList);
            return userVOIPage;
        } catch (Exception e) {
            log.error("查询菜单权限数据异常", e);
            return null;
        }
    }

    @Override
    public Map<String, Object> findMenus(UpmpMenuVO menu) {
        UpmpSysParam defaultInst = upmpSysParamService.getById(UpmpConstant.DEAFULT_INST_PARAM_ID);
        //当前用户ID
        UpmpUserInfoVO currentUser = RedpUpmpUtil.getCurrentUser(defaultInst.getPrimaryValue());
        log.info("currentUser:{}",currentUser);
        if(currentUser.isAdmin()){
            log.info("user {} is admin",currentUser.getLoginId());
        }
        Map<String, Object> result = new HashMap<>();
        try {
            LambdaQueryWrapper<UpmpMenu> queryWrapper = new LambdaQueryWrapper<>();
            findMenuCondition(queryWrapper, menu);
            List<UpmpMenu> menus = baseMapper.selectList(queryWrapper);

            List<Tree<UpmpMenu>> trees = new ArrayList<>();
            List<String> ids = new ArrayList<>();
            buildTrees(trees, menus, ids);

            result.put("ids", ids);
            if (UpmpConstant.TYPE_BUTTON.equals(menu.getType())) {
                result.put("rows", trees);
            } else {
                Tree<UpmpMenu> menuTree = TreeUtil.build(trees);
                result.put("rows", menuTree);
            }

            result.put("total", menus.size());
        } catch (NumberFormatException e) {
            log.error("查询菜单失败", e);
            result.put("rows", null);
            result.put("total", 0);
        }
        return result;
    }

    @Override
    public List<UpmpMenu> findMenuList(UpmpMenuVO menu) {
        LambdaQueryWrapper<UpmpMenu> queryWrapper = new LambdaQueryWrapper<>();
        findMenuCondition(queryWrapper, menu);
        queryWrapper.orderByAsc(UpmpMenu::getId);
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public void createMenu(UpmpMenu menu) {

        UpmpUserInfoVO user = CommonUtils.getCurrentUser(upmpSysParamService);
        menu.setOprId(user.getId());
        menu.setCreateTime(DateUtil.getDateFormat(new Date(), DateUtil.FULL_TIME_WITH_MILL_SPLIT_PATTERN));
        menu.setStatus("1");
        setMenu(menu);
        this.save(menu);
    }

    @Override
    public void updateMenu(UpmpMenu menu) throws Exception {
        UpmpUserInfoVO user = CommonUtils.getCurrentUser(upmpSysParamService);
        menu.setLastOprId(user.getId());
        menu.setLastUpdateTime(DateUtil.getDateFormat(new Date(), DateUtil.FULL_TIME_WITH_MILL_SPLIT_PATTERN));
        menu.setStatus("1");
        setMenu(menu);
        baseMapper.updateById(menu);

        // 查找与这些菜单/按钮关联的用户
        List<String> userIds = this.baseMapper.findUserIdsByMenuId(String.valueOf(menu.getId()));
        // 重新将这些用户的角色和权限缓存到 Redis中
        this.upmpUserManager.loadUserPermissionRoleRedisCache(userIds);
    }

    @Override
    public void deleteMeuns(String[] menuIds) throws Exception {
        this.delete(Arrays.asList(menuIds));
        for (String menuId : menuIds) {
            // 查找与这些菜单/按钮关联的用户
            List<String> userIds = this.baseMapper.findUserIdsByMenuId(String.valueOf(menuId));
            // 重新将这些用户的角色和权限缓存到 Redis中
            this.upmpUserManager.loadUserPermissionRoleRedisCache(userIds);
        }

    }

    /**
     * 用户常用功能菜单
     *
     * @param menu
     * @return
     */
    @Override
    public Map<String, Object> findMenusNoCommon(UpmpMenuVO menu) throws RedpException {
        Map<String, Object> result = new HashMap<>();
        //获取当前登录人信息
        UpmpUserInfoVO user = CommonUtils.getCurrentUser(upmpSysParamService);
        List<UserCommonFunVO> commonMenusVOList = null;
        try {
            LambdaQueryWrapper<UpmpMenu> queryWrapper = new LambdaQueryWrapper<>();
            if (!StringUtils.isEmpty(menu.getType())) {
                queryWrapper.eq(UpmpMenu::getType, menu.getType());
            }
            if (!StringUtils.isEmpty(menu.getChannelType())) {
                queryWrapper.eq(UpmpMenu::getChannelType, menu.getChannelType());
            }
            commonMenusVOList = userCommonFunService.findCommonMenus(user.getInstId(), user.getId());
            if (commonMenusVOList != null) {
                for (UserCommonFunVO commonMenuVO : commonMenusVOList) {
                    if (!StringUtils.isEmpty(commonMenuVO.getId())) {
                        queryWrapper.ne(UpmpMenu::getId, commonMenuVO.getId());
                    }
                }
            } else {
                System.out.println("==================commonMenus=null");
            }

            List<UpmpMenu> menus = baseMapper.selectList(queryWrapper);

            List<Tree<UpmpMenu>> trees = new ArrayList<>();
            List<String> ids = new ArrayList<>();
            buildTrees(trees, menus, ids);

            result.put("ids", ids);
            if (UpmpConstant.TYPE_BUTTON.equals(menu.getType())) {
                result.put("rows", trees);
            } else {
                Tree<UpmpMenu> menuTree = TreeUtil.build(trees);
                result.put("rows", menuTree);
            }

            result.put("total", menus.size());
        } catch (NumberFormatException e) {
            log.error("查询菜单失败", e);
            result.put("rows", null);
            result.put("total", 0);
        }
        return result;
    }

    /**
     * 根据菜单名menuName获取URL
     * @param menuName
     */
    @Override
    public String findMenuUrl(String menuName) {

        return this.baseMapper.findMenuUrl(menuName);
//        UpmpMenu menu = this.baseMapper.selectOne(new LambdaQueryWrapper<UpmpMenu>().eq(UpmpMenu::getMenuName, menuName));
//        return menu.getComponent();
    }

    private void buildTrees(List<Tree<UpmpMenu>> trees, List<UpmpMenu> menus, List<String> ids) {
        menus.forEach(menu -> {
            ids.add(menu.getId().toString());
            Tree<UpmpMenu> tree = new Tree<>();
            tree.setId(menu.getId().toString());
            tree.setKey(tree.getId());
            tree.setParentId(StringUtils.isEmpty(menu.getParentId()) ? "0" : menu.getParentId().toString());
            tree.setText(menu.getMenuName());
            tree.setTitle(tree.getText());
            tree.setChannelType(menu.getChannelType());
            tree.setIcon(menu.getIcon());
            tree.setComponent(menu.getComponent());
            tree.setCreateTime(menu.getCreateTime());
            tree.setModifyTime(menu.getLastUpdateTime());
            tree.setPath(menu.getPath());
            tree.setOrder(menu.getMenuIndex());
            tree.setPermission(menu.getPerms());
            tree.setType(menu.getType());
            trees.add(tree);
        });
    }


    private void setMenu(UpmpMenu menu) {
        if (StringUtils.isEmpty(menu.getParentId()))
            menu.setParentId(UpmpConstant.TOP_MENU_PARENT_ID);
        if (MenuTypeEnum.BUTTON.equals(menu.getType())) {
            menu.setPath(null);
            menu.setIcon(null);
            menu.setComponent(null);
        }
    }

    private void findMenuCondition(LambdaQueryWrapper<UpmpMenu> queryWrapper, UpmpMenuVO menu) {
        if (!StringUtils.isEmpty(menu.getType())) {
            queryWrapper.eq(UpmpMenu::getType, menu.getType());
        }
        if (!StringUtils.isEmpty(menu.getChannelType())) {
            queryWrapper.eq(UpmpMenu::getChannelType, menu.getChannelType());
        }
        if (!StringUtils.isEmpty(menu.getMenuName()) && !StringUtils.isEmpty(menu.getPerms())) {
            queryWrapper.and(wq -> wq.like(UpmpMenu::getMenuName, menu.getMenuName()).or().like(UpmpMenu::getPerms, menu.getPerms()));
        } else if (!StringUtils.isEmpty(menu.getMenuName()) && StringUtils.isEmpty(menu.getPerms())) {
            queryWrapper.like(UpmpMenu::getMenuName, menu.getMenuName());
        } else if (StringUtils.isEmpty(menu.getMenuName()) && !StringUtils.isEmpty(menu.getPerms())) {
            queryWrapper.or().like(UpmpMenu::getPerms, menu.getPerms());
        }
        if (!StringUtils.isEmpty(menu.getCreateTimeFrom()) && !StringUtils.isEmpty(menu.getCreateTimeTo())) {
            queryWrapper
                    .ge(UpmpMenu::getCreateTime, menu.getCreateTimeFrom())
                    .le(UpmpMenu::getCreateTime, menu.getCreateTimeTo());
        }
    }


    private void delete(List<String> menuIds) {
        removeByIds(menuIds);

        LambdaQueryWrapper<UpmpMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(UpmpMenu::getParentId, menuIds);
        List<UpmpMenu> menus = baseMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(menus)) {
            List<String> menuIdList = new ArrayList<>();
            menus.forEach(m -> menuIdList.add(m.getId()));
            this.delete(menuIdList);
        }
    }

    /**
     * 判断请求渠道类型
     * @param request
     * @return
     */
    @Override
    public ChannelTypeEnum getChannel(String userType, HttpServletRequest request) {
        String userAgent = request.getHeader("user-agent").toLowerCase();
//移动端访问
        if (userAgent.indexOf("android")!=-1 || userAgent.indexOf("iphone") != -1 || userAgent.indexOf("ipad") != -1){//移动端
            if(userAgent.indexOf("micromessenger")!=-1){//移动端微信
                return ChannelTypeEnum.BSPS_H5;
            }else if(userAgent.indexOf("alipayclient")!=-1){//移动端支付宝
                return null;
            }else{ //移动端app
                return ChannelTypeEnum.APP;
            }
        }else {
            //PC端访问
            if(UserTypeEnum.THIRD.getType().equals(userType)){//PC网站商城
                return ChannelTypeEnum.MALL_PC;
            }if(UserTypeEnum.BSPS.getType().equals(userType)){//商户服务PC
                return ChannelTypeEnum.BSPS_PC;
            }else {
                return ChannelTypeEnum.UPMP;
            }
        }
    }

}
